package JET.graphics;

import JET.geom.Rect2d;
import JET.geom.Vec2d;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JScrollPane;
import JET.physics.Mass;
import JET.physics.Spring;
import JET.physics.Wall;
import JET.Constants;
import JET.Centers.ControlCenter;
import JET.MouseStuff.MouseOTFMode;
import JET.Scene;
import JET.SceneHelper;
import JET.geom.Sec2d;
import JET.graphics.jogl.JoglGraphicPanel;
import JET.mygui.MyGuiHelper;
import JET.physics.RSpring;
import JET.physics.bodies.RigidBody;
import JET.physics.bodies.SpringBody;
import java.awt.Component;
import java.awt.Cursor;
import java.util.Collection;

/**
 *
 * @author 057Ry
 */
public class GraphicPanelMouseMotionListener implements MouseMotionListener, Constants
{
    static final ControlCenter CC = ControlCenter.getInstance();
    private final Rect2d engineRect;

    private Component owner;
    private GraphicPanel gp;
    private Scene scene;

    public GraphicPanelMouseMotionListener(Component owner) {
        engineRect = new Rect2d(0,0,0,0);
        this.owner = owner;
        gp = (GraphicPanel) owner;
        this.scene = CC.getScene(gp.getSceneName());
    }

    private void updateSystemCursor(MouseEvent evt)
    {
        Component jgp = (Component) owner;

        if ( CC.MC.getMouseOTFMode() != MouseOTFMode.DO_NOTHING )
        {
            switch( CC.MC.getMouseOTFMode() )
            {
                case SCROLL_GRAPHIC_PANEL : jgp.setCursor(new Cursor(Cursor.MOVE_CURSOR)); break;
            }
        }
        else 
            switch( CC.MC.getMouseMode() )
            {
                case CREATE_SQUARENET :
                case CREATE_CIRCLE :
//                    if ( evt.isShiftDown() && (CC.isDrawMainGrid() || CC.isDrawHelpGrid()))
                        jgp.setCursor( new Cursor(Cursor.CROSSHAIR_CURSOR) );
                    break;
                case ADD_SINGLE_MASS :
                case ADD_MANY_MASS :
                case ADD_SINGLE_SPRING :
                case ADD_SINGLE_RSPRING :
                case ADD_SINGLE_WALL :
                case COPY_SELECTED_ITEMS :
                case DO_NOTHING :
                case MOVE_MASSES :
                case REMOVE :
                case ROTATE :
                case SELECT_ALL_ITEMS :
                case SELECT_MASSES :
                case SELECT_SPRINGS :
                case SELECT_WALLS :
                case SET_MOVEABLE :
                    jgp.setCursor(Cursor.getDefaultCursor());
                    break;

            }
    }

    private void updateGeomCursorsData(MouseEvent evt)
    {
        if ( evt.isShiftDown() && (scene.GC.isDrawMainGrid() || scene.GC.isDrawHelpGrid()))
        {
            scene.EC.setDrawCursor(true);
            
            double modValueX = 1., modValueY= 1.;

            if ( scene.GC.isDrawMainGrid() )
            {
                modValueX = gp.getMainGriddX();
                modValueY = gp.getMainGriddY();
            }
            if ( scene.GC.isDrawHelpGrid() )
            {
                modValueX = gp.getHelpGriddX();
                modValueY = gp.getHelpGriddY();
            }

            double extraX = gp.scrToEngineX(evt.getX()) % modValueX;
            double x = gp.scrToEngineX(evt.getX()) - extraX;

            double extraY = gp.scrToEngineY(evt.getY()) % modValueY;
            double y = gp.scrToEngineY(evt.getY()) - extraY;

            Vec2d v[] = new Vec2d[4];
            
            Vec2d m = new Vec2d( gp.scrToEngineX(evt.getX()), gp.scrToEngineY(evt.getY()));
            v[0] = new Vec2d(x, y);
            v[1] = new Vec2d(x+modValueX, y);
            v[2] = new Vec2d(x+modValueX, y+modValueY);
            v[3] = new Vec2d(x, y+modValueY);

            int closest=0;
            double lowestMag = 1000000.;
            double mag=0.;
            for(int i=0; i<4; i++)
                if( (mag=v[i].getSubbed(m).getMagnitudeSquared())<=lowestMag )
                {
                    lowestMag = mag;
                    closest = i;
                }

            scene.EC.engCursorLastPos.become( scene.EC.engCursor );
            scene.EC.engCursor.become(v[closest]);
            scene.EC.scrCursor.setXY( gp.engineToScrX(v[closest].x), gp.engineToScrY(v[closest].y) );
            scene.EC.engCursorMoveVec.setXY(scene.EC.engCursor.getX() - scene.EC.engCursorLastPos.getX(),
                                      scene.EC.engCursor.getY() - scene.EC.engCursorLastPos.getY());

            // Set what cursor is pointing
            if (v[closest].x%gp.getMainGriddX()==0 && v[closest].y%gp.getMainGriddY()==0)
                scene.EC.setCursorTarger(GeomCursorTarget.MAIN_GRID);
            else if (v[closest].x%gp.getHelpGriddX()==0 && v[closest].y%gp.getHelpGriddY()==0)
                scene.EC.setCursorTarger(GeomCursorTarget.HELP_GRID);
        }
        else
        {
            scene.EC.setDrawCursor(false);

            scene.EC.engCursorLastPos.become( scene.EC.engCursor );
            scene.EC.engCursor.setXY( gp.scrToEngineX(evt.getX()), gp.scrToEngineY(evt.getY()));
            scene.EC.scrCursor.setXY( evt.getX(), evt.getY() );
            scene.EC.engCursorMoveVec.setXY(scene.EC.engCursor.getX() - scene.EC.engCursorLastPos.getX(),
                                      scene.EC.engCursor.getY() - scene.EC.engCursorLastPos.getY());
        }
    }

    private void updateCurrentBodyBoundingArea()
    {
        if (scene.EC.currentBody!=null) {
            scene.EC.currentBody.updateBoundingArea();
        }
    }

    
    public void mouseDragged(MouseEvent evt) 
    {
        // ------ mouse move vector ------
        double dx = evt.getXOnScreen() - CC.MC.mouseLastPosOnScreen.getX();
        double dy = evt.getYOnScreen() - CC.MC.mouseLastPosOnScreen.getY();
        CC.MC.mouseMoveVec.setXY( dx, dy );
        // -------------------------------

        // ------ cursor position update ------
        updateGeomCursorsData(evt);
        // ------------------------------------

        // ------ sustem cursor update ------
        updateSystemCursor(evt);
        // ----------------------------------

        CC.GUIC.setMouseScreenPos(evt);
        CC.GUIC.setMouseEnginePos(evt);

        // ------ update Actual Body BouningBox ----
        //updateCurrentBodyBoundingArea();
        // -----------------------------------------
        
        if ( CC.MC.getMouseOTFMode() != MouseOTFMode.DO_NOTHING )
        {
            switch( CC.MC.getMouseOTFMode() )
            {
                case SCROLL_GRAPHIC_PANEL : doScrollGraphicPanel(evt); break;
                case SCALE_ACTION_FRAME_NW : doScaleActionFrameNW(evt); break;
                case SCALE_ACTION_FRAME_NE : doScaleActionFrameNE(evt); break;
                case SCALE_ACTION_FRAME_SW : doScaleActionFrameSW(evt); break;
                case SCALE_ACTION_FRAME_SE : doScaleActionFrameSE(evt); break;
                case SCALE_ACTION_FRAME_N : doScaleActionFrameN(evt); break;
                case SCALE_ACTION_FRAME_S : doScaleActionFrameS(evt); break;
                case SCALE_ACTION_FRAME_W : doScaleActionFrameW(evt); break;
                case SCALE_ACTION_FRAME_E : doScaleActionFrameE(evt); break;
            }
        }
        else 
            switch( CC.MC.getMouseMode() )
            {
                case ADD_MANY_MASS :  doAddManyMass2d(evt); break;
                case MOVE_MASSES : doMoveManyMass2d(evt); break;
                case CREATE_CIRCLE :    doCreateCircle(evt); break;
                case CREATE_SQUARENET : doCreateSquareNet(evt); break;
                case SELECT_ALL_ITEMS : doSelectAll(evt); break;
                case SELECT_MASSES :    doSelectMasses(evt); break;
                case SELECT_MASSES_IN_ORDER : doSelectMassesInOrder(evt); break;
                case SELECT_SPRINGS :   doSelectSprings(evt); break;
                case SELECT_RSPRINGS :  doSelectRSprings(evt); break;
                case SELECT_WALLS :     doSelectWalls(evt); break;
                case ROTATE :           doRotate(evt); break;
                case SCALE :            doScale(evt); break;
            }
        
        CC.MC.mouseLastPos.setXY( evt.getX(), evt.getY() );
        CC.MC.mouseLastPosOnScreen.setXY( evt.getXOnScreen(), evt.getYOnScreen() );
        CC.MC.mouseEvent = evt;
    }

    public void mouseMoved(MouseEvent evt)
    {
        // ------ mouse move vector ------
        double dx = evt.getXOnScreen() - CC.MC.mouseLastPosOnScreen.getX();
        double dy = evt.getYOnScreen() - CC.MC.mouseLastPosOnScreen.getY();
        CC.MC.mouseMoveVec.setXY( dx, dy );
        // -------------------------------

        // ------ cursor position update ------
        updateGeomCursorsData(evt);
        // ------------------------------------

        // ------ sustem cursor update ------
        updateSystemCursor(evt);
        // ----------------------------------

        CC.GUIC.setMouseScreenPos(evt);
        CC.GUIC.setMouseEnginePos(evt);
        
        // ------ update Actual Body BouningBox ----
        //updateCurrentBodyBoundingArea();
        // -----------------------------------------
        
        switch( CC.MC.getMouseMode() )
        {
            case MOVE_MASSES : doDrawCatchArea(evt); break;
            case ADD_SINGLE_WALL : doDrawCatchArea(evt); break;
            case ADD_SINGLE_SPRING : doDrawCatchArea(evt); break;
            case SET_MOVEABLE : doDrawCatchArea(evt); break;
        }
        
        CC.MC.mouseLastPos.setXY( evt.getX(), evt.getY() );
        CC.MC.mouseLastPosOnScreen.setXY( evt.getXOnScreen(), evt.getYOnScreen() );
        CC.MC.mouseEvent = evt;
        owner.repaint();
    }

    public void doAddManyMass2d(MouseEvent evt)
    {
        if ( CC.continous_ADD_MANY_MASS2D )
        {
            CC.addManyMass2dVec2d.become( scene.EC.engCursor );
        }
    }
    
    public void doMoveManyMass2d(MouseEvent evt)
    {
        switch( CC.MC.getMouseModeAlt(CC.MC.getMouseMode())) {
            case CLOSEST :
                doMoveManyMass2dClosest(evt);
                break;
            case SPECYFIC :
                doMoveManyMass2dSpecyfic(evt);
                break;
        }
    }
    private void doMoveManyMass2dClosest(MouseEvent evt) {
        // Update temp mass engine position according to actual mouse engine position
        if (CC.MC.mouseObject1!=null)
        {
            Mass m = (Mass)CC.MC.mouseObject1;
            m.getPosition().become( scene.EC.engCursor );

            // Store last event data and update view
            CC.MC.mouseEvent = evt;
            owner.repaint();
        }
    }
    private void doMoveManyMass2dSpecyfic(MouseEvent evt) {
        if ( CC.continous_MOVE_MANY_MASS2D && CC.ctrlMass2dList.size()>0 )
        {
            for(Mass mass : CC.ctrlMass2dList )
            {
                if (evt.isControlDown())
                {
                    mass.getPosition().setX( scene.EC.engCursor.getX() );
                    mass.getPosition().setY( scene.EC.engCursor.getY() );
                }
                else
                {
                    mass.getPosition().addX( scene.EC.engCursorMoveVec.getX() );
                    mass.getPosition().addY( scene.EC.engCursorMoveVec.getY() );
                }
                mass.setLastPosition( mass.getPosition() );
            }

            CC.MC.mouseEvent = evt;
            owner.repaint();
        }
        else if ( !scene.EC.selectionGroup.getMassList().isEmpty() )
        {
            for(Mass mass : scene.EC.selectionGroup.getMassList() )
            {
                if (evt.isControlDown())
                {
                    mass.getPosition().setX( scene.EC.engCursor.getX() );
                    mass.getPosition().setY( scene.EC.engCursor.getY() );
                }
                else
                {
                    mass.getPosition().addX( scene.EC.engCursorMoveVec.getX() );
                    mass.getPosition().addY( scene.EC.engCursorMoveVec.getY() );
                }
                mass.setLastPosition( mass.getPosition() );
            }
            CC.MC.mouseEvent = evt;
            owner.repaint();
        }
        else if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            Collection<Mass> massCol = sb.getMassListSync();
            synchronized(massCol) {
                for(Mass mass : massCol) {
                    if (evt.isControlDown()) {
                        mass.getPosition().setX( scene.EC.engCursor.getX() );
                        mass.getPosition().setY( scene.EC.engCursor.getY() );
                    }
                    else {
                        mass.getPosition().addX( scene.EC.engCursorMoveVec.getX() );
                        mass.getPosition().addY( scene.EC.engCursorMoveVec.getY() );
                    }
                    mass.setLastPosition( mass.getPosition() );
                }
            }

            CC.MC.mouseEvent = evt;
            owner.repaint();
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            RigidBody rb = (RigidBody) scene.EC.currentBody;
            if (evt.isControlDown()) {
//                mass.getPosition().setX( scene.EC.engCursor.getX() );
//                mass.getPosition().setY( scene.EC.engCursor.getY() );
            }
            else {
                rb.position.add( scene.EC.engCursorMoveVec );
            }
            CC.MC.mouseEvent = evt;
            owner.repaint();
        }

        if (scene.EC.currentBody!=null) {
            scene.EC.currentBody.updateBoundingArea();
        }
    }
    public void doDrawCatchArea(MouseEvent evt) {
        CC.MC.mouseEvent = evt;
        owner.repaint();
    }

    public void doRotate(MouseEvent evt)
    {
        // Mouse Engine Pos
        Vec2d pos = new Vec2d( scene.EC.engCursor ) ;

        Mass tmpMass = new Mass(0., 0., 0.);

        if ( !CC.MC.mouseVec.equals(pos) )
        {
            Vec2d vec = new Vec2d(pos);
            vec.sub(CC.MC.mouseVec);

            double angle = vec.getAngleX();
            
            for (int i=0; i<scene.EC.selectionGroup.getMassList().size(); i++)
            {
                Mass mass = scene.EC.selectionGroup.getMassList().get(i);
                tmpMass.become(mass);
                tmpMass.getPosition().sub(CC.MC.mouseVec);
                tmpMass.getPosition().rotate(angle);
                tmpMass.getPosition().add(CC.MC.mouseVec);
                
                scene.EC.transformMassList.get(i).become(tmpMass);
            }
            
            owner.repaint();
        }
    }

    public void doScale(MouseEvent evt)
    {
        Vec2d pos = new Vec2d( scene.EC.engCursor );

        Mass tmpMass = new Mass(0., 0., 0.);

        //if ( CC.MC.mouseVec.getX() != pos.getX() )
        //{
            Vec2d vec = new Vec2d(pos);
            vec.sub(CC.MC.mouseVec);
            System.out.println("vec = "+vec);

            double scaleFactor = 1.;

            if (vec.getX() > 0)
                scaleFactor = 1 + vec.getX()/100.;
            else if (vec.getX() < 0)
                scaleFactor = Math.abs( 100. / (vec.getX()-100) );
            else
                scaleFactor = 1.;

            for (int i=0; i<scene.EC.selectionGroup.getMassList().size(); i++)
            {
                Mass mass = scene.EC.selectionGroup.getMassList().get(i);
                tmpMass.become(mass);
                tmpMass.getPosition().sub(CC.MC.mouseVec);
                tmpMass.getPosition().scale(scaleFactor);
                tmpMass.getPosition().add(CC.MC.mouseVec);

                scene.EC.transformMassList.get(i).become(tmpMass);
            }

            owner.repaint();
        //}
    }
    
    public void doScrollGraphicPanel(MouseEvent evt)
    {
        GraphicPanel gp = (GraphicPanel) owner;
        double moveScale = 1;
        switch (gp.getGraphicMode()) {
            case Swing :
                JScrollPane sPane = MyGuiHelper.getFirstScrollPaneAncestor(owner);
                Point viewportPos = sPane.getViewport().getViewPosition();
                int maxVPx = (int)( gp.getWidth() - sPane.getViewport().getWidth() );
                int maxVPy = (int)( gp.getHeight() - sPane.getViewport().getHeight() );

                int newVPx = (int)(viewportPos.getX() - CC.MC.mouseMoveVec.getX() * moveScale);
                int newVPy = (int)(viewportPos.getY() - CC.MC.mouseMoveVec.getY() * moveScale);
                if ( newVPx<0 ) newVPx = 0;
                if ( newVPy<0 ) newVPy = 0;
                if ( newVPx>maxVPx ) newVPx=maxVPx;
                if ( newVPy>maxVPy ) newVPy=maxVPy;
                sPane.getViewport().setViewPosition( new Point( newVPx, newVPy) );
                sPane.getViewport().updateUI();
                break;
            case OpenGL :
                    JoglGraphicPanel jgp = (JoglGraphicPanel) gp;

                    jgp.viewX += (float)(CC.MC.mouseMoveVec.getX() * moveScale);
                    jgp.viewY -= (float)(CC.MC.mouseMoveVec.getY() * moveScale);
                    jgp.display();
                break;
        }
        
    }

    public void doSelectAll(MouseEvent evt)
    {
        GraphicPanel gp = (GraphicPanel) owner;
        Vec2d moveEngineVec = new Vec2d( gp.scrToEngineX(evt.getX()), gp.scrToEngineY(evt.getY()) );
        // Selection rectangle jest zdefiniowany w przestrzeni swiata symulacji
        scene.EC.selectionRect = new Rect2d(CC.MC.mouseVec, moveEngineVec);

        scene.EC.tempSelectGroup.clear();
        for (Mass mass : SceneHelper.getMassesInRect(scene, scene.EC.selectionRect))
            scene.EC.tempSelectGroup.addMass(mass);

        for (Spring spring : SceneHelper.getSpringsInRect(scene, scene.EC.selectionRect))
            scene.EC.tempSelectGroup.addSpring(spring);

        for (RSpring rs : SceneHelper.getRSpringsInRect(scene, scene.EC.selectionRect))
            scene.EC.tempSelectGroup.addRSpring(rs);

        for (Wall wall : SceneHelper.getWallsInRect(scene, scene.EC.selectionRect))
            scene.EC.tempSelectGroup.addWall(wall);

        owner.repaint();
    }
    public void doSelectMasses(MouseEvent evt)
    {
        GraphicPanel gp = (GraphicPanel) owner;
        Vec2d moveEngineVec = new Vec2d( gp.scrToEngineX(evt.getX()), gp.scrToEngineY(evt.getY()) );
        // Selection rectangle jest zdefiniowany w przestrzeni swiata symulacji
        scene.EC.selectionRect = new Rect2d(CC.MC.mouseVec, moveEngineVec);

        scene.EC.tempSelectGroup.clear();
        for (Mass mass : SceneHelper.getMassesInRect(scene, scene.EC.selectionRect))
            scene.EC.tempSelectGroup.addMass(mass);
        owner.repaint();
    }
    public void doSelectSprings(MouseEvent evt)
    {
        GraphicPanel gp = (GraphicPanel) owner;
        Vec2d moveEngineVec = new Vec2d( gp.scrToEngineX(evt.getX()), gp.scrToEngineY(evt.getY()) );
        // Selection rectangle jest zdefiniowany w przestrzeni swiata symulacji
        scene.EC.selectionRect = new Rect2d(CC.MC.mouseVec, moveEngineVec);

        scene.EC.tempSelectGroup.clear();
        for (Spring spring : SceneHelper.getSpringsInRect(scene, scene.EC.selectionRect))
            scene.EC.tempSelectGroup.addSpring(spring);

        owner.repaint();
    }
    public void doSelectRSprings(MouseEvent evt)
    {
        GraphicPanel gp = (GraphicPanel) owner;
        Vec2d moveEngineVec = new Vec2d( gp.scrToEngineX(evt.getX()), gp.scrToEngineY(evt.getY()) );
        // Selection rectangle jest zdefiniowany w przestrzeni swiata symulacji
        scene.EC.selectionRect = new Rect2d(CC.MC.mouseVec, moveEngineVec);

        scene.EC.tempSelectGroup.clear();
        for (RSpring rs : SceneHelper.getRSpringsInRect(scene, scene.EC.selectionRect))
            scene.EC.tempSelectGroup.addRSpring(rs);

        owner.repaint();
    }
    public void doSelectWalls(MouseEvent evt)
    {
        GraphicPanel gp = (GraphicPanel) owner;
        Vec2d moveEngineVec = new Vec2d( gp.scrToEngineX(evt.getX()), gp.scrToEngineY(evt.getY()) );
        // Selection rectangle jest zdefiniowany w przestrzeni swiata symulacji
        scene.EC.selectionRect = new Rect2d(CC.MC.mouseVec, moveEngineVec);

        scene.EC.tempSelectGroup.clear();
        for (Wall wall : SceneHelper.getWallsInRect(scene, scene.EC.selectionRect))
            scene.EC.tempSelectGroup.addWall(wall);

        owner.repaint();
    }

    public void doCreateCircle(MouseEvent evt)
    {
        CC.MC.mouseVec2.become( scene.EC.engCursor );

        if (evt.isControlDown())
            CC.MC.mouseVec2.setY(CC.MC.mouseVec.getY());

        owner.repaint();
    }

    public void doCreateSquareNet(MouseEvent evt)
    {
        CC.MC.mouseVec2.become( scene.EC.engCursor );
        if (evt.isControlDown())
        {
            double y = CC.MC.mouseVec.getY()+(CC.MC.mouseVec2.getX()-CC.MC.mouseVec.getX());
            CC.MC.mouseVec2.setY(y);
        }
        
        owner.repaint();
    }

    private void doSelectMassesInOrder(MouseEvent evt)
    {
        GraphicPanel gp = (GraphicPanel) owner;
        scene.EC.vecList.add(new Vec2d(scene.EC.engCursor));

        if (scene.EC.vecList.size() > 1)
        {
            scene.EC.tempSelectGroup.clear();
            for(int i=0; i<scene.EC.vecList.size()-1; i++)
            {
                Sec2d sector = new Sec2d(scene.EC.vecList.get(i), scene.EC.vecList.get(i+1));

                Collection<SpringBody> sbCol = scene.getJETContext().getSpringBodyListSync();
                synchronized(sbCol) {
                    for(SpringBody sb : sbCol) {
                        Collection<Mass> massCol = sb.getMassListSync();
                        synchronized(massCol) {
                            for(Mass mass : massCol)
                                if (sector.isWithinBounds(mass.getPosition()) &&
                                    sector.getDistanceTo(mass.getPosition()) <= SELECTION_IN_ORDER_MAXIMUM_DISTANCE/gp.getViewScale())
                                    scene.EC.tempSelectGroup.addMass(mass);
                        }
                    }
                }
            }
        }

        owner.repaint();
    }

    private void doScaleActionFrameN(MouseEvent evt)
    {
        double oldBBHeight = CC.MC.mouseVec2.getY()-CC.MC.mouseVec.getY();
        double newBBHeight = scene.EC.engCursor.getY()-CC.MC.mouseVec.getY();
        if (oldBBHeight==0) return;
        double k = newBBHeight/oldBBHeight;

        Vec2d vec = new Vec2d();
        if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            // CC.tratransformSelectionGroup is 1 to 1 copy of an actual spring body
            for(int i=0; i<scene.EC.transformSelectionGroup.getMassList().size(); i++)
            {
                Mass selMass = scene.EC.transformSelectionGroup.getMassList().get(i);
                Mass asbMass = sb.getMassList().get(i);
                vec.become(selMass.getPosition());
                vec.subY(CC.MC.mouseVec.getY());
                vec.scaleY(k);
                vec.addY(CC.MC.mouseVec.getY());
                asbMass.getPosition().become(vec);
            }
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            // TODO: ...
        }
        
        updateCurrentBodyBoundingArea();
        owner.repaint();
    }
    private void doScaleActionFrameS(MouseEvent evt)
    {
        double oldBBHeight = CC.MC.mouseVec2.getY()-CC.MC.mouseVec.getY();
        double newBBHeight = CC.MC.mouseVec2.getY()-scene.EC.engCursor.getY();
        if (oldBBHeight==0) return;
        double k = newBBHeight/oldBBHeight;

        Vec2d vec = new Vec2d();
        if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            // CC.tratransformSelectionGroup is 1 to 1 copoy of an actual spring body
            for(int i=0; i<scene.EC.transformSelectionGroup.getMassList().size(); i++)
            {
                Mass selMass = scene.EC.transformSelectionGroup.getMassList().get(i);
                Mass asbMass = sb.getMassList().get(i);
                vec.become(selMass.getPosition());
                vec.subY(CC.MC.mouseVec2.getY());
                vec.scaleY(k);
                vec.addY(CC.MC.mouseVec2.getY());
                asbMass.getPosition().become(vec);
            }
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            // TODO: ...
        }
        
        updateCurrentBodyBoundingArea();
        owner.repaint();
    }

    private void doScaleActionFrameW(MouseEvent evt)
    {
        double oldBBWidth = CC.MC.mouseVec2.getX()-CC.MC.mouseVec.getX();
        double newBBWidth = CC.MC.mouseVec2.getX()-scene.EC.engCursor.getX();
        if (oldBBWidth==0) return;
        double k = newBBWidth/oldBBWidth;

        Vec2d vec = new Vec2d();
        if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            // CC.tratransformSelectionGroup is 1 to 1 copoy of an actual spring body
            for(int i=0; i<scene.EC.transformSelectionGroup.getMassList().size(); i++)
            {
                Mass selMass = scene.EC.transformSelectionGroup.getMassList().get(i);
                Mass asbMass = sb.getMassList().get(i);
                vec.become(selMass.getPosition());
                vec.subX(CC.MC.mouseVec2.getX());
                vec.scaleX(k);
                vec.addX(CC.MC.mouseVec2.getX());
                asbMass.getPosition().become(vec);
            }
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            // TODO: ...
        }

        updateCurrentBodyBoundingArea();
        owner.repaint();
    }
    private void doScaleActionFrameE(MouseEvent evt)
    {
        double oldBBWidth = CC.MC.mouseVec2.getX()-CC.MC.mouseVec.getX();
        double newBBWidth = scene.EC.engCursor.getX()-CC.MC.mouseVec.getX();
        if (oldBBWidth==0) return;
        double k = newBBWidth/oldBBWidth;

        Vec2d vec = new Vec2d();
        if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            // CC.tratransformSelectionGroup is 1 to 1 copoy of an actual spring body
            for(int i=0; i<scene.EC.transformSelectionGroup.getMassList().size(); i++)
            {
                Mass selMass = scene.EC.transformSelectionGroup.getMassList().get(i);
                Mass asbMass = sb.getMassList().get(i);
                vec.become(selMass.getPosition());
                vec.subX(CC.MC.mouseVec.getX());
                vec.scaleX(k);
                vec.addX(CC.MC.mouseVec.getX());
                asbMass.getPosition().become(vec);
            }
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            // TODO: ...
        }

        updateCurrentBodyBoundingArea();
        owner.repaint();
    }

    private void doScaleActionFrameNW(MouseEvent evt)
    {
        double oldBBWidth = CC.MC.mouseVec2.getX()-CC.MC.mouseVec.getX();
        double newBBWidth = CC.MC.mouseVec2.getX()-scene.EC.engCursor.getX();
        if (oldBBWidth==0) return;
        double kX = newBBWidth/oldBBWidth;

        double oldBBHeight = CC.MC.mouseVec2.getY()-CC.MC.mouseVec.getY();
        double newBBHeight = scene.EC.engCursor.getY()-CC.MC.mouseVec.getY();
        if (oldBBHeight==0) return;
        double kY = newBBHeight/oldBBHeight;

        Vec2d vec = new Vec2d();
        if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            // CC.tratransformSelectionGroup is 1 to 1 copoy of an actual spring body
            for(int i=0; i<scene.EC.transformSelectionGroup.getMassList().size(); i++)
            {
                Mass selMass = scene.EC.transformSelectionGroup.getMassList().get(i);
                Mass asbMass = sb.getMassList().get(i);
                vec.become(selMass.getPosition());
                vec.subX( CC.MC.mouseVec2.getX());
                vec.subY( CC.MC.mouseVec.getY());
                vec.scaleX(kX);
                vec.scaleY(kY);
                vec.addX(CC.MC.mouseVec2.getX());
                vec.addY(CC.MC.mouseVec.getY());
                asbMass.getPosition().become(vec);
            }
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            // TODO: ...
        }

        updateCurrentBodyBoundingArea();
        owner.repaint();
    }

    private void doScaleActionFrameNE(MouseEvent evt)
    {
        double oldBBWidth = CC.MC.mouseVec2.getX()-CC.MC.mouseVec.getX();
        double newBBWidth = scene.EC.engCursor.getX()-CC.MC.mouseVec.getX();
        if (oldBBWidth==0) return;
        double kX = newBBWidth/oldBBWidth;

        double oldBBHeight = CC.MC.mouseVec2.getY()-CC.MC.mouseVec.getY();
        double newBBHeight = scene.EC.engCursor.getY()-CC.MC.mouseVec.getY();
        if (oldBBHeight==0) return;
        double kY = newBBHeight/oldBBHeight;

        Vec2d vec = new Vec2d();
        if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            // CC.tratransformSelectionGroup is 1 to 1 copoy of an actual spring body
            for(int i=0; i<scene.EC.transformSelectionGroup.getMassList().size(); i++)
            {
                Mass selMass = scene.EC.transformSelectionGroup.getMassList().get(i);
                Mass asbMass = sb.getMassList().get(i);
                vec.become(selMass.getPosition());
                vec.subX( CC.MC.mouseVec.getX());
                vec.subY( CC.MC.mouseVec.getY());
                vec.scaleX(kX);
                vec.scaleY(kY);
                vec.addX(CC.MC.mouseVec.getX());
                vec.addY(CC.MC.mouseVec.getY());
                asbMass.getPosition().become(vec);
            }
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            // TODO: ...
        }

        updateCurrentBodyBoundingArea();
        owner.repaint();
    }

    private void doScaleActionFrameSW(MouseEvent evt)
    {
        double oldBBWidth = CC.MC.mouseVec2.getX()-CC.MC.mouseVec.getX();
        double newBBWidth = CC.MC.mouseVec2.getX()-scene.EC.engCursor.getX();
        if (oldBBWidth==0) return;
        double kX = newBBWidth/oldBBWidth;

        double oldBBHeight = CC.MC.mouseVec2.getY()-CC.MC.mouseVec.getY();
        double newBBHeight = CC.MC.mouseVec2.getY()-scene.EC.engCursor.getY();
        if (oldBBHeight==0) return;
        double kY = newBBHeight/oldBBHeight;

        Vec2d vec = new Vec2d();
        if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            // CC.tratransformSelectionGroup is 1 to 1 copoy of an actual spring body
            for(int i=0; i<scene.EC.transformSelectionGroup.getMassList().size(); i++)
            {
                Mass selMass = scene.EC.transformSelectionGroup.getMassList().get(i);
                Mass asbMass = sb.getMassList().get(i);
                vec.become(selMass.getPosition());
                vec.subX( CC.MC.mouseVec2.getX());
                vec.subY( CC.MC.mouseVec2.getY());
                vec.scaleX(kX);
                vec.scaleY(kY);
                vec.addX(CC.MC.mouseVec2.getX());
                vec.addY(CC.MC.mouseVec2.getY());
                asbMass.getPosition().become(vec);

            }
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            // TODO: ...
        }

        updateCurrentBodyBoundingArea();
        owner.repaint();
    }

    private void doScaleActionFrameSE(MouseEvent evt)
    {
        double oldBBWidth = CC.MC.mouseVec2.getX()-CC.MC.mouseVec.getX();
        double newBBWidth = scene.EC.engCursor.getX()-CC.MC.mouseVec.getX();
        if (oldBBWidth==0) return;
        double kX = newBBWidth/oldBBWidth;

        double oldBBHeight = CC.MC.mouseVec2.getY()-CC.MC.mouseVec.getY();
        double newBBHeight = CC.MC.mouseVec2.getY()-scene.EC.engCursor.getY();
        if (oldBBHeight==0) return;
        double kY = newBBHeight/oldBBHeight;


        Vec2d vec = new Vec2d();
        if (scene.EC.currentBody instanceof SpringBody)
        {
            SpringBody sb = (SpringBody) scene.EC.currentBody;
            // CC.tratransformSelectionGroup is 1 to 1 copoy of an actual spring body
            for(int i=0; i<scene.EC.transformSelectionGroup.getMassList().size(); i++)
            {
                Mass selMass = scene.EC.transformSelectionGroup.getMassList().get(i);
                Mass asbMass = sb.getMassList().get(i);
                vec.become(selMass.getPosition());
                vec.subX( CC.MC.mouseVec.getX());
                vec.subY( CC.MC.mouseVec2.getY());
                vec.scaleX(kX);
                vec.scaleY(kY);
                vec.addX(CC.MC.mouseVec.getX());
                vec.addY(CC.MC.mouseVec2.getY());
                asbMass.getPosition().become(vec);
            }
        }
        else if (scene.EC.currentBody instanceof RigidBody)
        {
            // TODO: ...
        }

        updateCurrentBodyBoundingArea();
        owner.repaint();
    }
}